﻿namespace Telerik.Web.Mvc.UI.Fluent.Tests
{
    using System.Data;
    using System.Linq;
    using UI.Tests;
    using Xunit;

    public class GridColumnFactoryTests
    {
        private static GridColumnFactory<T> Factory<T>()
            where T : class
        {
            return new GridColumnFactory<T>(GridTestHelper.CreateGrid<T>());
        }
        
        [Fact]
        public void Bound_column_by_name_and_type_data_row()
        {
            DataTable dataTable = new DataTable
            {
                Columns =
                {
                    new DataColumn("ID", typeof(int)),
                    new DataColumn("Name", typeof(string))
                }
            };

            GridColumnFactory<DataRowView> factory = Factory<DataRowView>();

            var builder = factory.Bound(typeof(int), "ID");

            Assert.Equal("ID", builder.Column.Title);

            dataTable.Rows.Add(1, "Test");

            Assert.Equal(1, ((GridBoundColumn<DataRowView, int?>)builder.Column).Value(dataTable.DefaultView[0]));
        }

        [Fact]
        public void Should_create_column_by_name_from_linq_to_object_source()
        {
            var grid = GridTestHelper.CreateGrid<Customer>();
            grid.DataSource = new[] {new Customer {Id = 1}}.AsQueryable();
            var factory = new GridColumnFactory<Customer>(grid);
            var builder = factory.Bound("Id");

            builder.Column.ShouldBeType<GridBoundColumn<Customer, int>>();
        }

        [Fact]
        public void Bound_column_by_name()
        {
            var customer = new Customer {Id = 1};

            GridColumnFactory<Customer> factory = Factory<Customer>();

            var builder = factory.Bound("Id");

            Assert.IsAssignableFrom<GridBoundColumn<Customer, int>>(builder.Column);

            Assert.Equal(1, ((GridBoundColumn<Customer, int>)builder.Column).Value(customer));
        }

        [Fact]
        public void Should_add_columns_to_grid_when_autogenerate_is_true()
        {
            GridColumnFactory<Customer> factory = Factory<Customer>();
            factory.AutoGenerate(true);

            Assert.Equal(7, factory.Container.Columns.Count);
        }

        [Fact]
        public void Should_not_add_columns_if_autogenerate_is_false_and_no_columns_declared()
        {
            GridColumnFactory<Customer> factory = Factory<Customer>();
            factory.AutoGenerate(false);

            Assert.Empty(factory.Container.Columns);
        }

        [Fact]
        public void Should_add_both_autogenerated_columns_and_declared_columns_when_autogenerate_is_true()
        {
            const int expectedColumnCount = 8;

            GridColumnFactory<Customer> factory = Factory<Customer>();
            factory.AutoGenerate(true);
            factory.Bound(c => c.Address);
            
            Assert.Equal(expectedColumnCount, factory.Container.Columns.Count);
        }

        [Fact]
        public void Should_add_columns_once_when_multiple_calls_to_autogenerate()
        {
            const int expectedColumnCount = 7;

            GridColumnFactory<Customer> factory = Factory<Customer>();
            factory.AutoGenerate(true);
            factory.AutoGenerate(true);
            factory.AutoGenerate(true);
            
            Assert.Equal(expectedColumnCount, factory.Container.Columns.Count);
        }

        [Fact]
        public void Should_set_Component_AutoGenerateColumns_to__the_same_value_as_AutoGenerate()
        {
            GridColumnFactory<Customer> factory = Factory<Customer>();
            factory.AutoGenerate(true);

            Assert.True(factory.Container.AutoGenerateColumns);
        }

        [Fact]
        public void Should_execute_ColumnAction_for_each_autogenerated_column()
        {
            int calledCounter = 0;
            const int expectedTimesCalled = 7;

            GridColumnFactory<Customer> factory = Factory<Customer>();

            factory.AutoGenerate(c => ++calledCounter);

            calledCounter.ShouldEqual(expectedTimesCalled);
        }
    }
}
